﻿#include "common.h"
#include "FFmpegRecording.h"

#if defined(_MSVC_LANG) && _MSVC_LANG >= 201703L
std::wstring str2wstr(const std::string& str)
{
    int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
    std::wstring wstrTo(size_needed, 0);
    MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
    return wstrTo;
}

std::string wstr2str(const std::wstring& wstr)
{
    int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
    std::string strTo(size_needed, 0);
    WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
    return strTo;
}
#endif

// 设备管理类
DeviceManager::DeviceManager()
{
    //av_output_audio_device_next();

    update_device_list();

    qDebug() << "设备管理类列表：";
    for (int i = 0; i < input_device_list_.size(); i++) {
        qDebug() << "音频输入设备" << i << "：" << input_device_list_[i].c_str();
    }
    for (int i = 0; i < output_device_list_.size(); i++) {
        qDebug() << "音频输出设备" << i << "：";
        qDebug() << "    driver: " << QString::fromStdString(output_device_list_[i]["driver"]) << "  friendly：" << QString::fromStdString(output_device_list_[i]["friendly"]);
    }
}

DeviceManager::~DeviceManager()
{
    clean_list();
}

// 获取默认麦克风等设备名称（FFmpeg 7.1.1 适用）
// 增强：优先返回 virtual-audio-capturer（虚拟扬声器），否则提示用户安装
std::string DeviceManager::get_default_device(MyIODeviceType input_type) {
    avdevice_register_all();
    std::string defaultDevice;
    AVDeviceInfoList* device_list = nullptr;
    const AVInputFormat* input_fmt = av_find_input_format("dshow");
    if (!input_fmt)
        return "";
    int ret = avdevice_list_input_sources(input_fmt, nullptr, nullptr, &device_list);
    if (ret < 0 || !device_list)
        return "";
    // 新增：优先查找 virtual-audio-capturer
    if (input_type == MyIODeviceType::Speaker) {
        for (int i = 0; i < device_list->nb_devices; ++i) {
            const AVDeviceInfo* info = device_list->devices[i];
            if (info && info->device_name && strstr(info->device_name, "virtual-audio-capturer")) {
                defaultDevice = info->device_name;
                qDebug() << "检测到 virtual-audio-capturer，优先使用：" << defaultDevice.c_str();
                avdevice_free_list_devices(&device_list);
                return defaultDevice;
            }
        }
        // 没有 virtual-audio-capturer，尝试 Stereo Mix
        for (int i = 0; i < device_list->nb_devices; ++i) {
            const AVDeviceInfo* info = device_list->devices[i];
            if (info && info->device_name && info->device_description && (strstr(info->device_description, "Stereo Mix") || strstr(info->device_description, "立体声混音"))) {
                defaultDevice = info->device_name;
                qDebug() << "检测到立体声混音，使用：" << defaultDevice.c_str();
                avdevice_free_list_devices(&device_list);
                return defaultDevice;
            }
        }
        // 没有虚拟驱动也没有立体声混音，提示用户
        qDebug() << "未检测到 virtual-audio-capturer 或 立体声混音，无法直接录制扬声器。请安装 virtual-audio-capturer 或启用声卡的立体声混音功能。";
        avdevice_free_list_devices(&device_list);
        return "";
    }
    // 其它类型保持原有逻辑
    for (int i = 0; i < device_list->nb_devices; ++i) {
        const AVDeviceInfo* info = device_list->devices[i];
        if (info && info->device_description && info->device_name) {
            if (input_type == MyIODeviceType::Camera && (strstr(info->device_description, "Camera") || strstr(info->device_description, "摄像"))) {
                defaultDevice = info->device_name;
                qDebug() << "默认摄像机设备(内部名)：" << defaultDevice.c_str();
                break;
            }
            else if (input_type == MyIODeviceType::Microphone && (strstr(info->device_description, "Microphone") || strstr(info->device_description, "麦克风") || ((strstr(info->device_description, "Default") && strstr(info->device_description, "Audio Device"))))) {
                defaultDevice = info->device_name;
                qDebug() << "默认麦克风设备(内部名)：" << defaultDevice.c_str();
                break;
            }
            else {
                defaultDevice = info->device_name;
            }
        }
    }
    avdevice_free_list_devices(&device_list);
    qDebug() << "最终返回的设备内部名：" << defaultDevice.c_str();
    return defaultDevice;
}

void DeviceManager::enumerate_audio_render_devices()
{
    HRESULT hr;

    // 初始化COM库
    hr = CoInitialize(nullptr);
    if (FAILED(hr)) {
        qDebug() << "CoInitialize failed with error: " << hr;
        return;
    }
    // 如果COM库已经初始化过，返回值将是RPC_E_CHANGED_MODE，这通常不是错误
    if (hr == RPC_E_CHANGED_MODE) {
        qDebug() << "COM library is already initialized in a different mode";
    }

    IMMDeviceEnumerator* pEnum = nullptr;
    hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, IID_PPV_ARGS(&pEnum));
    if (FAILED(hr)) {
        qDebug() << "CoCreateInstance failed";
        // 在返回之前，确保释放COM库
        CoUninitialize();
        return;
    }

    IMMDeviceCollection* pDevices = nullptr;
    hr = pEnum->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pDevices);
    if (FAILED(hr)) {
        qDebug() << "EnumAudioEndpoints failed";
        pEnum->Release();
        // 在返回之前，确保释放COM库
        CoUninitialize();
        return;
    }

    UINT count = 0;
    pDevices->GetCount(&count);
    for (UINT i = 0; i < count; ++i) {
        IMMDevice* pDevice = nullptr;
        pDevices->Item(i, &pDevice);

        IPropertyStore* pProps = nullptr;
        pDevice->OpenPropertyStore(STGM_READ, &pProps);

        PROPVARIANT varName;
        PropVariantInit(&varName);
        pProps->GetValue(PKEY_Device_FriendlyName, &varName);

        // 输出设备友好名称
        qDebug() << "Audio Output Device" << i << ":" << QString::fromWCharArray(varName.pwszVal);

        PropVariantClear(&varName);
        pProps->Release();
        pDevice->Release();
    }

    // 释放设备集合和枚举器
    pDevices->Release();
    pEnum->Release();

    // 在使用完COM库后，释放它
    CoUninitialize();
}

const std::vector<std::string> DeviceManager::get_input_devices()
{
    return input_device_list_;
}

//const std::vector<std::string> DeviceManager::get_output_devices()
//{
//    return output_device_name_list_;
//}

const std::vector<std::map<std::string, std::string>> DeviceManager::get_output_device_list() noexcept
{
    return output_device_list_;
}

const unsigned int __stdcall DeviceManager::get_sound_devices_count()
{
    return waveOutGetNumDevs();
}

void DeviceManager::clean_list()
{
    if (input_device_list_.size() > 0) {
        input_device_list_.clear();
    }
    /*if (output_device_name_list_.size() > 0) {
        output_device_name_list_.clear();
    }*/
    if (output_device_list_.size() > 0) {
        output_device_list_.clear();
    }
}

void DeviceManager::update_device_list()
{
    clean_list();
    avdevice_register_all();
    std::string defaultDevice;
    AVDeviceInfoList* device_list = nullptr;
    const AVInputFormat* input_fmt = av_find_input_format("dshow");
    if (!input_fmt)
        throw std::runtime_error("Could not find dshow input format");
    int ret = avdevice_list_input_sources(input_fmt, nullptr, nullptr, &device_list);
    if (ret < 0 || !device_list)
        throw std::runtime_error("Could not list input devices");
    for (int i = 0; i < device_list->nb_devices; ++i) {
        const AVDeviceInfo* info = device_list->devices[i];
        if (info && info->device_description)  // 初始化输入列表
            input_device_list_.push_back(info->device_description);
    }
    avdevice_free_list_devices(&device_list);

    // 初始化输出设备列表，使用Core Audio API获取驱动名和友好名
    //output_device_list_.clear();
    HRESULT hr = CoInitialize(nullptr);
    if (FAILED(hr) && hr != RPC_E_CHANGED_MODE) {
        qDebug() << "CoInitialize failed";
        return;
    }
    IMMDeviceEnumerator* pEnum = nullptr;
    hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, IID_PPV_ARGS(&pEnum));
    if (FAILED(hr)) {
        qDebug() << "CoCreateInstance failed";
        if (hr != RPC_E_CHANGED_MODE) CoUninitialize();
        return;
    }
    IMMDeviceCollection* pDevices = nullptr;
    hr = pEnum->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pDevices);
    if (FAILED(hr)) {
        qDebug() << "EnumAudioEndpoints failed";
        pEnum->Release();
        if (hr != RPC_E_CHANGED_MODE) CoUninitialize();
        return;
    }
    UINT count = 0;
    pDevices->GetCount(&count);
    for (UINT i = 0; i < count; ++i) {
        IMMDevice* pDevice = nullptr;
        pDevices->Item(i, &pDevice);
        // 获取设备驱动名（设备ID，唯一标识）
        LPWSTR deviceId = nullptr;
        pDevice->GetId(&deviceId);
        // 获取设备友好名
        IPropertyStore* pProps = nullptr;
        pDevice->OpenPropertyStore(STGM_READ, &pProps);
        PROPVARIANT varName;
        PropVariantInit(&varName);
        pProps->GetValue(PKEY_Device_FriendlyName, &varName);
        // 存入map，第一个成员driver为设备ID，第二个成员friendly为友好名
        std::map<std::string, std::string> dev;
        // deviceId 是 wchar_t*，转为 std::string（UTF-8编码，保证中文不乱码）
        QString qid = QString::fromWCharArray(deviceId);
        dev["driver"] = std::string(qid.toLocal8Bit().constData());
        // varName.pwszVal 是 wchar_t*，转为 std::string（UTF-8编码，保证中文不乱码）
        QString qname = QString::fromWCharArray(varName.pwszVal);
        dev["friendly"] = qname.toLocal8Bit().constData();
        output_device_list_.push_back(dev);
        // 释放
        CoTaskMemFree(deviceId);
        PropVariantClear(&varName);
        pProps->Release();
        pDevice->Release();
    }
    pDevices->Release();
    pEnum->Release();
    if (hr != RPC_E_CHANGED_MODE) CoUninitialize();
    // 注释：output_device_list_的每个 map，第一个成员 driver 为设备驱动名（设备ID），第二个成员 friendly 为友好名（中文/英文名）
}

void DeviceManager::enumerateSoundDevices(DWORD deviceIndex, LPCTSTR* deviceDesc, LPCTSTR* deviceName)
{
    WAVEOUTCAPS deviceCaps;
    if (waveOutGetDevCaps(deviceIndex, &deviceCaps, sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR) {
        *deviceName = deviceCaps.szPname;
        // 设备描述可以设置为设备名称或者其他相关信息
        *deviceDesc = deviceCaps.szPname;
    }
    else {
        *deviceName = nullptr;
        *deviceDesc = nullptr;
    }
}



